/***************************************************************************
 *   Copyright (C) 2007 by Alexandre Masselot,,,   *
 *   alex@alex-laptop   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "peaktheomsmsfactorybasic.h"

namespace bol {

  PeakTheoMsmsFactoryBasic::PeakTheoMsmsFactoryBasic()
  : PeakTheoMsMsFactory()
  {
    m_fragSeries.resize(sizeof(Pchargemask)*8);
  }

  void PeakTheoMsmsFactoryBasic::setSeries(const string& serieslist, const unsigned int c){
    m_chargeMapper.addCharge(c);
    boost::regex re("([by])([\\+]+)?");
    boost::cmatch matches;
    typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
    boost::char_separator<char> sep(",");
    tokenizer tokens(serieslist, sep);
    for (tokenizer::iterator tok_iter = tokens.begin();
         tok_iter != tokens.end(); ++tok_iter){
           string strtok(*tok_iter);
           if(boost::regex_match(strtok.c_str(), matches, re)){
             string series(matches[1]);
             string strcharges(matches[2]);
             unsigned int charge;
             if(strcharges==""){
               charge=1;
             }else{//i.e. "++"
               charge=strcharges.length();
             }
             int dir;
             if(series=="y"){
               dir=-1;
             }else{
               dir=1;
             }
             double startMass;
             ///@todo check those staring value (that shoudl be without H+)
             if(series=="y")
               startMass=18.0105746-1.00728;
             if(series=="b")
               startMass=-(15.9949146+1.00783);
             cout<<c<<"+ -> BasicFragSeries("<<series<<","<<dir<<","<<charge<<","<<startMass<<")"<<endl;
             const unsigned int index=series2index(series);
             m_fragSeries[c].push_back(new BasicFragSeries(strtok, dir, charge, startMass, index));
           }else{
             cerr<<"UNKNOWN series ["<<*tok_iter<<"]"<<endl;
             exit(1);
           }
         }
         std::cout << endl;
  }


  PeakTheoMsmsFactoryBasic::~PeakTheoMsmsFactoryBasic()
  {
  }

  void PeakTheoMsmsFactoryBasic::computeTheoMasses(
      const Peptide& pept,
      Spectrum<PeakTheoMsms*>& spectrum,
      const unsigned int charge,
      const bool showDescription
                                                  )const{
        double totmass=pept.getMass();
        unsigned char const* first=pept.sequence();
        unsigned char const* last=first+pept.length()-1;
        const unsigned projcharge=chargeMapper()[charge];
        for(vector<const BasicFragSeries*>::const_iterator it=m_fragSeries[projcharge].begin(); it<m_fragSeries[projcharge].end(); it++){
          unsigned char const *begin, *end, *beginsave, *endsave;
          const int dir=(*it)->m_dir;
      ///@todo if we want to avoid first or last fragment, info should be put here! (in fact, idem for -H20 like conditions)
          if(dir>0){
            begin=first;
            end=last;
            beginsave=begin+2;
            endsave=end;
            if(beginsave>endsave)
              break;
          }else{
            begin=last;
            end=first;
            beginsave=last-1;
            endsave=end-1;
            if(endsave>beginsave)
              break;
          }
          const double fact=(*it)->m_factor;
          double m=(*it)->m_startMass*fact+MassCalculator::MASS_HPLUS;
          ChargedSeries zSeries=(*it)->m_chargedSeries;
          const unsigned int index=zSeries.index;
          const string series=(*it)->m_name;
          const Pchargemask chargemask=1<<((int)(.01+1/(*it)->m_factor));//+.01 for rounding effect
          int i=0;
          bool save=false;
          for(unsigned char const* c=begin; c!=end; c+=dir){
            m+=fact*AminoAcid::char2mass(*c);
            if(c==beginsave)
              save=true;
            if(c==endsave)
              break;
            if(save){
              char *descr=NULL;
              if(showDescription){
                string s=series+"("+boost::lexical_cast<string>(i)+")";
                descr=new char[s.length()+1];
                memcpy(descr, s.c_str(), s.length());
                descr[s.length()]=0;
              }
              spectrum.push_back(new PeakTheoMsms(m, chargemask, c-first, index, descr));
            }
            i++;
          }
        }
        sort(spectrum.begin(), spectrum.end(), Peak::ltptr);

  }
}
